/**
 * @file port_i2c.c
 * @brief
 * @author lijingjie (lijingjie@pthyidh.com)
 * @date 2024-11-06 04:05:57
 *
 * @copyright Copyright (c) 2024 by 深圳市鹏天微智能科技有限公司, All Rights Reserved.
 */

/* ==================== [Includes] ========================================== */

#include "xf_hal_port.h"

#if XF_HAL_I2C_IS_ENABLE

#include <stdio.h>
#include <stdlib.h>

#include "pt3220.h"
#include "drvs.h"

#include "xf_utils.h"
#include "xf_init.h"

/* ==================== [Defines] =========================================== */

#define XF_HAL_I2C_DEFAULT_HOSTS            XF_HAL_I2C_HOSTS_MASTER
#define XF_HAL_I2C_DEFAULT_ENABLE           false
#define XF_HAL_I2C_DEFAULT_ADDRESS_WIDTH    XF_HAL_I2C_ADDRESS_WIDTH_7BIT
#define XF_HAL_I2C_DEFAULT_ADDRESS          0x56
#define XF_HAL_I2C_DEFAULT_MEM_ADDR         0
#define XF_HAL_I2C_DEFAULT_MEM_ADDR_EN      false
#define XF_HAL_I2C_DEFAULT_MEM_ADDR_WIDTH   XF_HAL_I2C_MEM_ADDR_WIDTH_8BIT
#define XF_HAL_I2C_DEFAULT_SPEED            1000000
#define XF_HAL_I2C_DEFAULT_SCL_NUM          4
#define XF_HAL_I2C_DEFAULT_SDA_NUM          5
#define XF_HAL_I2C_DEFAULT_TIMEOUT          0

#define TAG   ("PORT_I2C")

/* ==================== [Typedefs] ========================================== */

/* ==================== [Static Prototypes] ================================= */

/* ==================== [Static Variables] ================================== */

/* ==================== [Macros] ============================================ */

/* ==================== [Global Functions] ================================== */

/* ==================== [Static Functions] ================================== */

static uint16_t pt_i2c_read(uint8_t dev_addr, uint8_t *data, uint8_t length)
{
    return i2c_read((dev_addr << 1) | 1, length, data);
}

static uint16_t pt_i2c_write_mem(uint8_t dev_addr, uint8_t reg_addr, const void *data, uint16_t len)
{
    uint8_t *buff_tx = (uint8_t *)xf_malloc((sizeof(uint8_t) * len) + 1);
    if (buff_tx == NULL) {
        return XF_ERR_NO_MEM;
    }
    memcpy(buff_tx, &reg_addr, 1);
    memcpy(buff_tx + 1, data, len);

    uint16_t ret = i2c_write((dev_addr << 1) | 0, len + 1, buff_tx);

    xf_free(buff_tx);

    return ret;
}

static uint16_t pt_i2c_write(uint8_t dev_addr, const void *data, uint16_t len)
{
    return i2c_write((dev_addr << 1) | 0, len, data);
}

static xf_err_t port_i2c_open(xf_hal_dev_t *dev)
{
    return XF_OK;
}

static xf_err_t port_i2c_ioctl(xf_hal_dev_t *dev, uint32_t cmd, void *config)
{
    xf_hal_i2c_config_t *i2c_config = (xf_hal_i2c_config_t *)config;

    if (cmd == XF_HAL_I2C_CMD_DEFAULT) {
        i2c_config->hosts           = XF_HAL_I2C_DEFAULT_HOSTS;
        i2c_config->enable          = XF_HAL_I2C_DEFAULT_ENABLE;
        i2c_config->address_width   = XF_HAL_I2C_DEFAULT_ADDRESS_WIDTH;
        i2c_config->address         = XF_HAL_I2C_DEFAULT_ADDRESS;
        i2c_config->mem_addr        = XF_HAL_I2C_DEFAULT_MEM_ADDR;
        i2c_config->mem_addr_en     = XF_HAL_I2C_DEFAULT_MEM_ADDR_EN;
        i2c_config->mem_addr_width  = XF_HAL_I2C_DEFAULT_MEM_ADDR_WIDTH;
        i2c_config->speed           = XF_HAL_I2C_DEFAULT_SPEED;
        i2c_config->scl_num         = XF_HAL_I2C_DEFAULT_SCL_NUM;
        i2c_config->sda_num         = XF_HAL_I2C_DEFAULT_SDA_NUM;
        i2c_config->timeout_ms      = XF_HAL_I2C_DEFAULT_TIMEOUT;
        dev->platform_data          = config;

        return XF_OK;
    }

    if (cmd == XF_HAL_I2C_CMD_ALL) {
        return XF_OK;
    }

    if ((cmd & XF_HAL_I2C_CMD_HOSTS
            || cmd & XF_HAL_I2C_CMD_SCL_NUM
            || cmd & XF_HAL_I2C_CMD_SDA_NUM)
            && i2c_config->enable) {
        return XF_ERR_NOT_SUPPORTED;
    }

    if (cmd & XF_HAL_I2C_CMD_SPEED && i2c_config->enable) {
        // 不支持动态设置，disable后设置后enable
        return XF_ERR_NOT_SUPPORTED;
    }

    if (cmd & XF_HAL_I2C_CMD_ADDRESS_WIDTH && i2c_config->enable) {
        // 不支持动态设置，disable后设置后enable
        return XF_ERR_NOT_SUPPORTED;
    }

    if (cmd & XF_HAL_I2C_CMD_ENABLE) {
        if (i2c_config->enable) {
            uint8_t i2c_speed = 0;
            switch (i2c_config->speed) {
            case (100 * 1000):
                i2c_speed = SCLK_100K;
                break;

            case (200 * 1000):
                i2c_speed = SCLK_200K;
                break;

            case (400 * 1000):
                i2c_speed = SCLK_400K;
                break;

            default:
                XF_LOGI(TAG, "scl_pin:%d, sda_pin:%d, speed:%d", i2c_config->scl_num, i2c_config->sda_num, i2c_config->speed);
                XF_LOGE(TAG, "setting speed error.");
                return XF_ERR_INVALID_PORT;
            }
            i2c_init(i2c_config->scl_num, i2c_config->sda_num, i2c_speed);
        } else {
            i2c_deinit();
            return XF_ERR_UNINIT;
        }
    }

    return XF_OK;
}

static int port_i2c_read(xf_hal_dev_t *dev, void *buf, size_t count)
{
    xf_hal_i2c_config_t *i2c_config = (xf_hal_i2c_config_t *)dev->platform_data;

    if (i2c_config->hosts == XF_HAL_I2C_HOSTS_MASTER && i2c_config->mem_addr_en == XF_HAL_I2C_MEM_ADDR_ENABLE) {
        return i2c_read_mem(i2c_config->address, i2c_config->mem_addr, count, buf);
    } else if (i2c_config->hosts == XF_HAL_I2C_HOSTS_MASTER && i2c_config->mem_addr_en != XF_HAL_I2C_MEM_ADDR_ENABLE) {
        return pt_i2c_read(i2c_config->address, buf, count);
    }

    return -XF_ERR_NOT_SUPPORTED;
}

static int port_i2c_write(xf_hal_dev_t *dev, const void *buf, size_t count)
{
    xf_hal_i2c_config_t *i2c_config = (xf_hal_i2c_config_t *)dev->platform_data;

    if (i2c_config->hosts == XF_HAL_I2C_HOSTS_MASTER && i2c_config->mem_addr_en == XF_HAL_I2C_MEM_ADDR_ENABLE) {
        return pt_i2c_write_mem(i2c_config->address, i2c_config->mem_addr, buf, count);
    } else if (i2c_config->hosts == XF_HAL_I2C_HOSTS_MASTER && i2c_config->mem_addr_en != XF_HAL_I2C_MEM_ADDR_ENABLE) {
        return pt_i2c_write(i2c_config->address, buf, count);
    }

    return -XF_ERR_NOT_SUPPORTED;
}

static xf_err_t port_i2c_close(xf_hal_dev_t *dev)
{
    return XF_OK;
}

static int xf_hal_i2c_reg(void)
{
    xf_driver_ops_t ops = {
        .open = port_i2c_open,
        .ioctl = port_i2c_ioctl,
        .write = port_i2c_write,
        .read = port_i2c_read,
        .close = port_i2c_close,
    };
    xf_hal_i2c_register(&ops);
    return XF_OK;
}

XF_INIT_EXPORT_PREV(xf_hal_i2c_reg);

#endif
